package cybertwin

import (
	_ "crypto/rsa"
	"cybertwin/utils/cryptotools"
	"cybertwin/utils/generator"

	"github.com/panjf2000/gnet/v2"
	log "github.com/sirupsen/logrus"

	//"github.com/panjf2000/gnet/v2/pkg/logging"
	"cybertwin/utils/protocol"
	"sync"
	// "time"
	//"google.golang.org/protobuf/proto"
	//"cybertwin/pb/model"
)

const (
	MAX_REQ_NUM   int = 1024
	PRIORITY_TYPE int = 8
)

type Cybertwin struct {
	gnet.BuiltinEventEngine
	scheduler
	eng         gnet.Engine
	reqClient   *gnet.Client
	Ctid        string
	Uid         string
	Ck2         []byte            // 用于和AP交互的对称密钥，也就是ck2
	CkeyDevSet  map[string][]byte // 用于与各个设备交互的对称密钥，也就是ck3
	UeInfoSetMu *sync.RWMutex
	UeInfoSet   map[string]*UE_INFO

	UeConnectSet map[string]bool

	Network string
	Addr    string

	// token
}

func (cbt *Cybertwin) Init() {
	cbt.CkeyDevSet = make(map[string][]byte)
	cbt.UeInfoSet = make(map[string]*UE_INFO)
	cbt.UeConnectSet = make(map[string]bool)
	cbt.UeInfoSetMu = &sync.RWMutex{}
}

func (cbt *Cybertwin) OnBoot(eng gnet.Engine) (action gnet.Action) {
	cbt.eng = eng
	// 申请空间
	cbt.CkeyDevSet = make(map[string][]byte)
	cbt.UeInfoSet = make(map[string]*UE_INFO)
	for i := 0; i < PRIORITY_TYPE; i++ {
		cbt.Req_Queue[i] = make(chan Request_Record, MAX_REQ_NUM)
		cbt.Resp_Queue[i] = make(chan Response_Record, MAX_REQ_NUM)
	}
	cbt.Resp_Buffer = make(map[BufferKey]*Response_Record)
	cbt.ReqOrResp = 0
	cbt.Req_routine_num = 0
	cbt.Req_max_routine_num = 4
	cbt.Req_routine_num_mu = &sync.Mutex{}
	cbt.Resp_routine_num = 0
	cbt.Resp_max_routine_num = 4
	cbt.Resp_routine_num_mu = &sync.Mutex{}

	ctClientEv := &Cybertwin_Client{
		cbt: cbt,
	}
	cbt.reqClient, _ = gnet.NewClient(ctClientEv)
	cbt.reqClient.Start()
	log.Infof("[OnBoot]-成功启动cybertwin，Addr=%s", cbt.Addr)
	return gnet.None
}

func (cbt *Cybertwin) OnOpen(conn gnet.Conn) (out []byte, action gnet.Action) {
	var cc = &contextInfo{
		connId: generator.RandomInt(1, 1000000),
	}
	conn.SetContext(cc)
	return
}

// OnTraffic 这个gnet创建服务器只处理来自ue的请求
func (cbt *Cybertwin) OnTraffic(conn gnet.Conn) (action gnet.Action) {
	codec := protocol.CodecUtils.AccessProtocolCodec
	var ueid string = conn.Context().(*contextInfo).ueid    // 此处：如果ue没有提前和ct进行token接入沟通，那么ueid会为"",从而使得后面的过程报错
	rawData, typeName, isEncrypt, err := codec.Decode(conn) // 最好在这一步能够得到ueid
	if err != nil {
		log.Errorf("[OnTraffic]-[Decode阶段]-decode异常:%s", err.Error())
		return gnet.Close
	}

	// 数据是否经过加密, 在这一步之前应该获得ueid，然后根据ueid提取对应的对称密钥
	var data []byte
	if isEncrypt && typeName != protocol.TYPE_UE_CYBERTWIN_REQUEST.GetName() {
		data, err = cryptotools.AES_Decrypt(rawData, cbt.Ck2)
		if err != nil {
			log.Errorln("[OnTraffic]-[Decrypt阶段]-使用cbt.Ck2解密出错：", err.Error())
			return
		}
	} else if isEncrypt {
		data, err = cryptotools.AES_Decrypt(rawData, cbt.CkeyDevSet[ueid])
		if err != nil {
			log.Errorln("[OnTraffic]-[Decrypt阶段]-使用ck3解密出错：", err.Error())
			return
		}
	} else {
		data = rawData
	}

	switch typeName {
	case protocol.TYPE_AP_INFORM_CYBERTWIN.GetName():
		//log.Infoln("[OnTraffic]-[TYPE_AP_INFORM_CYBERTWIN]-进入handler")
		err = cbt.handler_APInform(data)
		if err != nil {
			log.Errorf("[OnTraffic]-[TYPE_AP_INFORM_CYBERTWIN]-error=%s", err.Error())
		}
	case protocol.TYPE_ACCESS_CYBERTWIN.GetName():
		//log.Infoln("[OnTriffic]-[TYPE_ACCESS_CYBERTWIN]-进入handler")
		err = cbt.handler_UE_ACCESS_CYBERTWIN(data, conn)
		if err != nil {
			log.Errorf("[OnTraffic]-[TYPE_ACCESS_CYBERTWIN]-error=%s", err.Error())
		}
	case protocol.TYPE_UE_CYBERTWIN_REQUEST.GetName():
		cbt.handler_UE_CYBERTWIN_REQUEST(data, ueid)
	}

	return gnet.None
}

func (cbt *Cybertwin) OnClose(conn gnet.Conn, err error) (action gnet.Action) {
	context := conn.Context().(*contextInfo)
	cbt.UeInfoSetMu.RLock()
	ueinfo := cbt.UeInfoSet[context.ueid]
	cbt.UeInfoSetMu.RUnlock()
	ueinfo.status = UE_STATUS_DISCONNECTED
	log.Infof("[OnClose]-连接%d关闭，将ue状态置为disconnected", context.connId)
	return gnet.None
}

func (cbt *Cybertwin) OnShutdown(eng gnet.Engine) {
	cbt.reqClient.Stop()
}
